<?php
/**
 * Query2Result is a class with data manipulation methods
 *
 * @author Adam Zivner <adam.zivner@gmail.com>
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD license
 * @package Query2
 * @link http://query2.0o.cz
 */

class Query2Result implements Iterator, Countable
{
	/** @var resource - returned by mysql_query() */
	public $res;

	public function __construct($res) { $this->res = $res; }
	public function __destruct()      { mysql_free_result($this->res); }

	/**
	 * Return first (or $col, if given) column of the first line of the result.
	 *
	 * @param string $col
	 * @return false|string
	 */

	public function fetchOne($col = '')
	{
		$row = mysql_fetch_assoc($this->res);

		if(!$row)
			return false;
		else
			return strlen($col) ? $row[$col] : reset($row);
	}

	/**
	 * Fetch first (or $col, if given) column of all result rows.
	 *
	 * @param string $col
	 * @return array
	 */

	public function fetchCol($col = '')
	{
		$ret = array();

		while($c = $this->fetchOne($col))
			$ret[] = $c;

		return $ret;
	}

	/**
	 * Return associative array of first result row. You can specify which columns
	 * should be returned. If no columns are give, method returns all columns.
	 *
	 * @param string column1
	 * @param string column2 ...
	 * @return false|array
	 */

	public function fetchRow()
	{
		$row = mysql_fetch_assoc($this->res);

		if(!$row || func_num_args() == 0)
			return $row;
		else {
			$ret = array();

			foreach(is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args() as $col)
				$ret[$col] = $row[$col];

			return $ret;
		}
	}

	/**
	 * Fetch all result rows. You can specify which columns should be returned.
	 * If no columns are give, method returns all columns.
	 *
	 * @param string column1
	 * @param string column2 ...
	 * @return array
	 */

	public function fetchAll()
	{
		$args = func_get_args();
		$ret = array();

		while($row = call_user_func_array(array($this, "fetchRow"), $args))
			$ret[] = $row;

		return $ret;
	}

	/**
	 * Return all rows associated by given column(s). See http://query2.0o.cz for details.
	 *
	 * @param string $col1 - first assoc with this
	 * @param string $col2 - then assoc with this
	 * ...
	 *
	 * @return array
	 */

	public function fetchAssoc()
	{
		$cols = func_get_args();

		$arr = $this->fetchAll();
		$ret = array();

		foreach($arr as $row) {
			$cur =& $ret;

			foreach($cols as $col) {
				if(!isset($cur[$row[$col]]))
					$cur[$row[$col]] = array();

				$cur =& $cur[$row[$col]];
			}

			$cur[] = $row;
		}

		return $ret;
	}

	/**
	 * Return array("id" => "jmeno", ...) consisting of the first two columns
	 * of all result rows. Useful e.g. for fetching values for select box.
	 *
	 * @param string|integer $key - which column should be used for key
	 * @param string|integer $value - which column should be used for value
	 * @return array
	 */

	public function fetchPairs($key = 0, $value = 1)
	{
		$ret = array();

		while($row = mysql_fetch_array($this->res))
			$ret[$row[$key]] = $row[$value];

		return $ret;
	}

	public function numRows() { return mysql_num_rows($this->res); }

	// Countable interface
	public function count() { return $this->numRows(); }

	// Iterator interface

	private $idx = 0; // generate some (for each row unique) key
	private $row; // current row
	
	/**
	 * Rewind the result set to the start (or to the given row). It's both
	 * directly callable and implementation of Iterator interface
	 *
	 * @param integer $row - to which row result set should be rewinded
	 */

	public function rewind($row = 0)
	{
		if(mysql_num_rows($this->res))
			mysql_data_seek($this->res, 0);

		$this->idx = 0;
	}

	public function current() { return $this->row; }
	public function key()     { return $this->idx; }
	public function next()    { $this->idx++; }

	public function valid() 
	{
		$this->row = $this->fetchRow();

		return $this->row ? true : false;
	}
}